package org.ne.springboot.utils.PaperHandleUtils.PaperContentCheckUtils;


import jakarta.servlet.http.HttpServletResponse;
import org.ne.springboot.utils.PaperHandleUtils.FontCheckUtils.FormatReportServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.ne.springboot.utils.PaperHandleUtils.CommonUtils.WordUtils.extractTextFromDocx;
import static org.ne.springboot.utils.PaperHandleUtils.FontCheckUtils.FontCheckUtils.fontCheck;


/**
 * @author wey
 * @date 2025/8/25 下午9:33 08
 **/
public class PaperHandleUtils {
    private static final SparkClient SPARK_CLIENT = new SparkClient();
    private static final FormatReportServlet FRS = new FormatReportServlet();
    private static final Logger log = LoggerFactory.getLogger(PaperHandleUtils.class);

    //spark
    public static List<Map<String, Object>> contentAnalyze(String question, MultipartFile file, String model, HttpServletResponse response) throws IOException {
        SPARK_CLIENT.setModel(model);
        List<String> lines = extractTextFromDocx(file);
        List<Map<String, Object>> list = new ArrayList<>();
        try {
            for (String line : lines) {
                if (line.trim().length() > 50) {

                    if (isClientDisconnected(response)) {
                        log.warn("Client disconnected");
                        return null;
                    }

                    Map<String, Object> res =  SPARK_CLIENT.processRequest(question, line);
                    Map<String, Object> resMap = new HashMap<>();

                    resMap.put("original", line);
                    resMap.put("result", res);

                    list.add(resMap);
                }
            }
        } catch (Exception e) {
            if (isConnectionException(e)) {
                log.warn("客户端连接已断开，下载中止: {}", e.getMessage());
                // 这里可以进行一些清理工作，然后安静地退出，无需抛出异常
                return null;
            } else {
                // 重新抛出其他非连接类型的IOException
                throw e;
            }
        }

        return list;
    }



    public static void fontCheckReport(MultipartFile file, HttpServletResponse response) throws Exception {
        // 设置响应头，告诉浏览器返回的是ZIP文件

        response.setContentType("application/zip");
        String encodedZipName = URLEncoder.encode("格式检查结果.zip", StandardCharsets.UTF_8);

        response.setHeader("Content-Disposition", "attachment; filename=\"" + encodedZipName + "\"");
        // 创建一个字节数组输出流，用于暂存标红文档
        ByteArrayOutputStream markedDocStream = new ByteArrayOutputStream();
        // 创建一个字节数组输出流，用于暂存报告文档
        ByteArrayOutputStream reportStream = new ByteArrayOutputStream();

        // 用于保存格式错误信息
        Map<String, List<String>> formatErrors = null;

        try {
            // 1. 执行格式检查并生成标红文档
            // 这里需要重构你的fontCheck方法，使其能够将结果写入提供的输出流
            formatErrors = fontCheck(markedDocStream, file);

            // 2. 生成报告文档
            // 这里需要重构你的FormatReportServlet，使其能够将报告写入提供的输出流
            FRS.doGet (formatErrors, reportStream);

            // 3. 创建ZIP输出流，直接将ZIP内容写入response的输出流
            try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
                // 添加标红文档到ZIP
                ZipEntry markedDocEntry = new ZipEntry("格式检查标红文档.docx");
                zos.putNextEntry(markedDocEntry);
                zos.write(markedDocStream.toByteArray());
                zos.closeEntry();

                // 添加报告文档到ZIP
                ZipEntry reportEntry = new ZipEntry("格式错误检查报告.docx");
                zos.putNextEntry(reportEntry);
                zos.write(reportStream.toByteArray());
                zos.closeEntry();
            }

        } catch (Exception e) {
            // 异常处理
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.setContentType("text/plain;charset=UTF-8");
            response.getWriter().write("处理失败: " + e.getMessage());
            throw e;
        }
    }



    /**
     * 检查客户端连接是否已断开[8](@ref)
     */
    private static boolean isClientDisconnected(HttpServletResponse response) {
        try {
            // 原理：如果响应已经提交（isCommitted），通常意味着数据已经开始发送给客户端。
            // 尝试向输出流写入一个空字节并刷新，如果客户端已断开，这里会抛出IOException。
            if (response.isCommitted()) {
                // 对于已提交的响应，通过写入测试判断
                response.getOutputStream().write(new byte[0]);
                response.getOutputStream().flush();
            }
            log.info("Connection status: {}", response.getStatus());
            // 如果响应未提交，此方法返回false不代表连接一定正常，但多数容器在写入时才会真正暴露问题。
            return false;
        } catch (IOException e) {
            // 发生IO异常，很可能连接已断开
            return true;
        }
    }

    /**
     * 判断异常是否与连接断开相关[8](@ref)
     */
    private static boolean isConnectionException(Throwable throwable) {
        if (throwable == null) {
            return false;
        }
        String message = throwable.getMessage();
        // 检查异常信息中是否包含连接断开的典型描述
        if (message != null) {
            String lowerCaseMessage = message.toLowerCase();
            if (lowerCaseMessage.contains("broken pipe") ||
                    lowerCaseMessage.contains("connection reset by peer") ||
                    lowerCaseMessage.contains("connection reset") ||
                    lowerCaseMessage.contains("客户端断开连接")) { // 可根据日志中的实际异常信息补充关键词
                return true;
            }
        }

        // 检查异常链
        return isConnectionException(throwable.getCause());
    }

}



